#! /usr/bin/env python3

import argparse
import shutil
import subprocess
import sys
import tempfile
import os

from oclintscripts import cmake
from oclintscripts import environment
from oclintscripts import path
from oclintscripts import process
from oclintscripts import version

OCLINT_MODULES = ['core', 'metrics', 'rules', 'reporters', 'driver']

arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('module_name', nargs='?', choices=['all'] + OCLINT_MODULES, default='all')
arg_parser.add_argument('-show', '--show', action="store_true")
arg_parser.add_argument('-clean', '--clean', action="store_true")
arg_parser.add_argument('-j', type=int, default=0)
arg_parser.add_argument('-as-dep', '--as-dep', action="store_true")
arg_parser.add_argument('-llvm-root', '--llvm-root', default=path.build.clang_install_dir)
arg_parser.add_argument('-no-ninja', '--no-ninja', action='store_true')
args = arg_parser.parse_args()

def clean_module(module_name):
    test_path = path.oclint_module_test_dir(module_name)
    path.rm_f(test_path);

def build_command(module_extras, llvm_root, no_ninja, source_path):
    cmd_build = cmake.builder(source_path).test_build()
    if args.as_dep:
        cmd_build = cmake.builder(source_path)
    if not no_ninja:
        cmd_build.use_ninja()
    extras = {'LLVM_ROOT': llvm_root, 'GOOGLETEST_SRC': path.source.googletest_dir, 'GOOGLETEST_BUILD': path.build.googletest_build_dir}
    extras.update(module_extras)
    return cmd_build.append_dict(extras).str()

def test_result_path(module_name):
    return os.path.join(path.oclint_module_test_dir(module_name), 'testresults.txt')

def display_test_result(module_name):
    testresult_path = test_result_path(module_name)
    with open(testresult_path, 'r') as testresult_file:
        print(testresult_file.read())

def install_clang_headers_to_tmp():
    clang_headers_src_path = os.path.join(path.build.clang_install_dir, 'lib', 'clang', version.llvm_version(), 'include')
    clang_headers_dst_path = os.path.join(tempfile.gettempdir(), 'oclint-rules-test', 'clang')
    path.rm_f(clang_headers_dst_path)
    path.cp_r(clang_headers_src_path, clang_headers_dst_path)

def test_module(module_name, llvm_root, no_ninja, j):
    build_path = path.oclint_module_test_dir(module_name)
    source_path = path.oclint_module_source_dir(module_name)

    module_extras = {}
    if module_name == "rules" or module_name == "reporters" or module_name == "driver":
        module_extras['OCLINT_SOURCE_DIR'] = path.source.core_dir
        module_extras['OCLINT_BUILD_DIR'] = path.build.core_test_dir
    if module_name == "rules":
        module_extras['OCLINT_METRICS_SOURCE_DIR'] = path.source.metrics_dir
        module_extras['OCLINT_METRICS_BUILD_DIR'] = path.build.metrics_test_dir

    command = build_command(module_extras, llvm_root, no_ninja, source_path)

    current_dir = os.getcwd()
    path.mkdir_p(build_path)
    path.cd(build_path)
    process.call(command)
    if no_ninja:
        process.make(j)
    else:
        process.ninja(j)
    if not args.as_dep:
        if module_name == "rules":
            install_clang_headers_to_tmp()
        run_ctest_command = 'ctest --output-on-failure > ' + test_result_path(module_name)
        ctest_exit_code = subprocess.call(run_ctest_command, shell=True)
        display_test_result(module_name)
        if ctest_exit_code:
            sys.exit(ctest_exit_code)
    path.cd(current_dir)

build_modules = []
if args.module_name == 'all':
    build_modules.extend(OCLINT_MODULES)
else:
    build_modules.append(args.module_name)

if args.show:
    for module in build_modules:
        display_test_result(module)
    sys.exit(0)

if args.clean:
    for module in build_modules:
        clean_module(module)

for module in build_modules:
    test_module(module, args.llvm_root, args.no_ninja, args.j)
